﻿using Microsoft.CodeAnalysis.MSBuild;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Collections.Specialized.BitVector32;


#region 文件信息
/****************************************************************
*	公司名称：福建力和行智能科技有限公司
*   作    者：Jeff
*   CLR 版本：4.0.30319.42000
*   创建时间：1/1/2025 11:23:35 AM
*	用 户 名：zheqichen 
*   描述说明：
*
*   修改历史：
*		1）	修 改 人：
*			修改日期：
*			修改内容：			
*
*****************************************************************/
#endregion

namespace Lhxzn.LangExtractor
{
    /// <summary>
    /// 类    名:LngFileManager
    /// 描    述:语言档各类操作总管理器
    /// 修改时间:1/1/2025 11:23:35 AM
    /// </summary>
    public class LngFileManager
    {
        #region 成员变量

        #region private



        #endregion


        #region protected



        #endregion


        #region public
        /// <summary>
        /// 当前操作的语言包
        /// </summary>
        public LanguagePackage CurrentPackage { get; set; }

        /// <summary>
        /// 未翻译标注工具
        /// </summary>
        public AnnotationManager AnnotationManager { get; set; }

        /// <summary>
        /// 内容搜索工具
        /// </summary>
        public ContextSearcher ContextSearcher { get; set; } 

        /// <summary>
        /// 选择的语言文件名
        /// </summary>
        public string SelectedLngFileName { get; set; } = "";

        /// <summary>
        /// 选择的节点名
        /// </summary>
        public string SelectedSectionName { get; set; } = "";

        /// <summary>
        /// 存放匹配的语言档信息
        /// </summary>
        public class LangValueSelectItem
        {
            public string LanguageFileName { get; set; }
            public string Section { get; set; }
            public KeyValuePair<string, IniFile.KeyData> KeyValue { get; set; }

            public override string ToString()
            {
                return $"{KeyValue.Key}={KeyValue.Value}    (语言文件:{LanguageFileName}|| 节点:[{Section}])";
            }
        }
        #endregion

        #endregion


        #region 构造函数
        /// <summary>
        /// 函 数 名:构造函数
        /// 函数描述:默认构造函数
        /// 修改时间:1/1/2025 11:23:35 AM
        /// </summary>
        public LngFileManager()
        {
            ContextSearcher = new ContextSearcher(this);
            AnnotationManager = new AnnotationManager(this);
        }
        #endregion

        #region 父类函数重载、接口实现

        #endregion

        #region 函数

        #region private



        #endregion


        #region protected



        #endregion


        #region public
        /// <summary>
        /// 从lng文件中导入语言包
        /// </summary>
        /// <param name="UpdateStatusBar"></param>
        public void GetLngFileFromFile(Action<string> UpdateStatusBar)
        {
            if (CurrentPackage != null && MessageBox.Show("是否清空当前语言文件并导入新文件? ", "导入", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
            {
                return;
            }

            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Title = "选择一个语言文件";
            dlg.Filter = "语言文件 (*.lng)|*.lng";
            if (dlg.ShowDialog() == DialogResult.OK)
            {
                string selectedFilePath = dlg.FileName;
                string pakPath = Path.GetDirectoryName(selectedFilePath);
                CurrentPackage = new LanguagePackage(pakPath);
                LanguageFile file = new LanguageFile(selectedFilePath);
                file.ReadStream();
                CurrentPackage.LanguageFiles.Add(file);
                UpdateStatusBar.Invoke($"成功打开语言文件，保存路径:{file.FilePath}");
            }
        }

        /// <summary>
        /// 从文件夹中导入语言包
        /// </summary>
        /// <param name="UpdateStatusBar"></param>
        public void GetLngPakFromFolder(Action<string> UpdateStatusBar)
        {
            if (CurrentPackage != null && MessageBox.Show("是否清空当前语言文件并导入新文件? ", "导入", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
            {
                return;
            }

            FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();
            folderBrowserDialog.Description = "选择一个语言包";
            if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
            {
                string selectedPath = folderBrowserDialog.SelectedPath;
                CurrentPackage = new LanguagePackage(selectedPath);
                CurrentPackage.Load();
                UpdateStatusBar.Invoke($"成功打开语言包，保存路径:{CurrentPackage.Folder}");
            }
        }

        /// <summary>
        /// 从csproject中提取语言档并导入语言包
        /// </summary>
        /// <param name="PojectLoadUpdateStatusBar"></param>
        /// <param name="UpdateStatusBar"></param>
        /// <returns></returns>
        public async Task GetLngFileFromProject(Action<ProjectLoadProgress> PojectLoadUpdateStatusBar, Action<string> UpdateStatusBar)
        {
            if (CurrentPackage != null && MessageBox.Show("是否清空当前语言文件并导入新文件? ", "导入", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
            {
                return;
            }
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Title = "选择一个项目文件";
            dlg.Filter = "解决方案文件 (*.csproj)|*.csproj";
            if (dlg.ShowDialog() == DialogResult.OK)
            {
                string selectedFilePath = dlg.FileName;
                using var workspace = MSBuildWorkspace.Create();
                var progressReporter = new ProgressReporter(PojectLoadUpdateStatusBar);
                var project = await workspace.OpenProjectAsync(selectedFilePath, progressReporter);
                if (project == null)
                {
                    return;
                }
                CurrentPackage = new LanguagePackage(""); 
                LanguageFile file = await LangExtractorHelper.ExtractLangFromProject(project);
                CurrentPackage.LanguageFiles.Add(file);
                CurrentPackage.SetPackagePath(Path.GetDirectoryName(selectedFilePath) + "\\language");
                AnnotationManager.InitializeAnnotationDict(CurrentPackage);
                UpdateStatusBar.Invoke($"成功提取项目文件内的语言档，保存路径:{file.FilePath}");
            }
        }

        /// <summary>
        /// 从解决方案中提取并导入语言包
        /// </summary>
        /// <param name="PojectLoadUpdateStatusBar"></param>
        /// <param name="UpdateStatusBar"></param>
        /// <returns></returns>
        public async Task GetLngFileFromSolution(Action<ProjectLoadProgress> PojectLoadUpdateStatusBar, Action<string> UpdateStatusBar)
        {
            if (CurrentPackage != null && MessageBox.Show("是否清空当前语言文件并导入新文件? ", "导入", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
            {
                return;
            }
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Title = "选择一个解决方案文件";
            dlg.Filter = "解决方案文件 (*.sln)|*.sln";
            if (dlg.ShowDialog() == DialogResult.OK)
            {
                string selectedFilePath = dlg.FileName;
                using var workspace = MSBuildWorkspace.Create();
                var progressReporter = new ProgressReporter(PojectLoadUpdateStatusBar);
                var solution = await workspace.OpenSolutionAsync(selectedFilePath, progressReporter);
                if (solution == null)
                {
                    return;
                }
                CurrentPackage = await LangExtractorHelper.ExtractLangFromSolution(solution, Path.GetDirectoryName(selectedFilePath));
                AnnotationManager.InitializeAnnotationDict(CurrentPackage);
                UpdateStatusBar.Invoke($"成功提取解决方案内的语言档，保存路径:{CurrentPackage.Folder}");
            }
        }

        /// <summary>
        /// 补充语言包
        /// </summary>
        /// <param name="UpdateStatusBar"></param>
        public void CompeleteLngPakFromFile(Action<string> UpdateStatusBar)
        {
            if (CurrentPackage == null)
            {
                MessageBox.Show("请先导入语言包");
                return;
            }

            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Title = "选择一个语言文件";
            dlg.Filter = "语言文件 (*.lng)|*.lng";
            if (dlg.ShowDialog() == DialogResult.OK)
            {
                string selectedFilePath = dlg.FileName;
                string pakPath = Path.GetDirectoryName(selectedFilePath);
                LanguagePackage pak = new LanguagePackage(pakPath);
                LanguageFile file = new LanguageFile(selectedFilePath);
                file.ReadStream();
                pak.LanguageFiles.Add(file);
                CurrentPackage.MergeWith(pak, out Dictionary<string, List<string>> annotationsDict);
                AnnotationManager.InitializeAnnotationDict(annotationsDict);
                UpdateStatusBar.Invoke($"成功从语言文件{selectedFilePath}提取语言档，补充至当前语言包");
            }
        }

        /// <summary>
        /// 补充语言包
        /// </summary>
        /// <param name="UpdateStatusBar"></param>
        public void CompeleteLngPakFromFolder(Action<string> UpdateStatusBar)
        {
            if (CurrentPackage == null)
            {
                MessageBox.Show("请先导入语言包");
                return;
            }

            FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();
            folderBrowserDialog.Description = "选择一个语言包";
            if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
            {
                string selectedPath = folderBrowserDialog.SelectedPath;
                LanguagePackage pak = new LanguagePackage(selectedPath);
                pak.Load();
                CurrentPackage.MergeWith(pak, out Dictionary<string, List<string>> annotationsDict);
                AnnotationManager.InitializeAnnotationDict(annotationsDict);
                UpdateStatusBar.Invoke($"成功从语言包{selectedPath}提取语言档，补充至当前语言包");
            }
        }

        /// <summary>
        /// 补充语言包
        /// </summary>
        /// <param name="PojectLoadUpdateStatusBar"></param>
        /// <param name="UpdateStatusBar"></param>
        /// <returns></returns>
        public async Task CompeleteLngPakFromProject(Action<ProjectLoadProgress> PojectLoadUpdateStatusBar, Action<string> UpdateStatusBar)
        {
            if (CurrentPackage == null)
            {
                MessageBox.Show("请先导入语言包");
                return;
            }
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Title = "选择一个项目文件";
            dlg.Filter = "解决方案文件 (*.csproj)|*.csproj";
            if (dlg.ShowDialog() == DialogResult.OK)
            {
                using var workspace = MSBuildWorkspace.Create();
                var progressReporter = new ProgressReporter(PojectLoadUpdateStatusBar);
                var project = await workspace.OpenProjectAsync(dlg.FileName, progressReporter);
                if (project == null)
                {
                    return;
                }

                LanguagePackage pak = new LanguagePackage("");
                LanguageFile file = await LangExtractorHelper.ExtractLangFromProject(project);
                pak.LanguageFiles.Add(file);
                CurrentPackage.MergeWith(pak, out Dictionary<string, List<string>> annotationsDict);
                AnnotationManager.InitializeAnnotationDict(annotationsDict);
                UpdateStatusBar.Invoke($"成功从项目文件{dlg.FileName}提取语言档，补充至当前语言包");
            }
        }

        /// <summary>
        /// 补充语言包
        /// </summary>
        /// <param name="PojectLoadUpdateStatusBar"></param>
        /// <param name="UpdateStatusBar"></param>
        /// <returns></returns>
        public async Task CompeleteLngPakFromSolution(Action<ProjectLoadProgress> PojectLoadUpdateStatusBar, Action<string> UpdateStatusBar)
        {
            if (CurrentPackage == null)
            {
                MessageBox.Show("请先导入语言包");
                return;
            }

            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Title = "选择一个解决方案文件";
            dlg.Filter = "解决方案文件 (*.sln)|*.sln";
            if (dlg.ShowDialog() == DialogResult.OK)
            {
                string selectedFilePath = dlg.FileName;
                //MessageBox.Show("你选择了文件: " + selectedFilePath);
                using var workspace = MSBuildWorkspace.Create();
                var progressReporter = new ProgressReporter(PojectLoadUpdateStatusBar);
                var solution = await workspace.OpenSolutionAsync(selectedFilePath, progressReporter);
                if (solution == null)
                {
                    return;
                }
                LanguagePackage pak = await LangExtractorHelper.ExtractLangFromSolution(solution, Path.GetDirectoryName(selectedFilePath));
                CurrentPackage.MergeWith(pak,out Dictionary<string,List<string>> annotationsDict);
                AnnotationManager.InitializeAnnotationDict(annotationsDict);
                UpdateStatusBar.Invoke($"成功从解决方案{selectedFilePath}提取语言档，补充至当前语言包");
            }
        }

        /// <summary>
        /// 从语言文件导入语言值给标注处
        /// </summary>
        /// <returns></returns>
        public async Task ImportLangValueFromFile()
        {
            if (CurrentPackage == null)
            {
                MessageBox.Show("请先导入语言包");
                return;
            }
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Title = "选择一个语言文件";
            dlg.Filter = "语言文件 (*.lng)|*.lng";
            if (dlg.ShowDialog() != DialogResult.OK)
            {
                return;
            }

            string selectedFilePath = dlg.FileName;
            string pakPath = Path.GetDirectoryName(selectedFilePath);
            LanguagePackage pak = new LanguagePackage(pakPath);
            LanguageFile file = new LanguageFile(selectedFilePath);
            file.ReadStream();
            Dictionary<LangValueSelectItem, IEnumerable<LangValueSelectItem>> results = new Dictionary<LangValueSelectItem, IEnumerable<LangValueSelectItem>>();
            await Task.Run(() => {
                foreach (LanguageFile langfile in CurrentPackage.LanguageFiles)
                {
                    foreach (var sec in langfile.GetIniCache())
                    {
                        foreach (var kvp in sec.Value)
                        {
                            var annotions = AnnotationManager.GetAnnotations(Path.GetFileName(langfile.FilePath));
                            if (annotions == null)
                            {
                                continue;
                            }
                            var annotion = annotions.FirstOrDefault(item => item.Contains(kvp.Key + "=" + kvp.Value));
                            if (annotion == null)
                            {
                                continue;
                            }
                            var result = file.GetIniCache().SelectMany(sec => sec.Value
                            .Select(kvp => new LangValueSelectItem
                            {
                                LanguageFileName = Path.GetFileName(langfile.FilePath),
                                Section = sec.Key,
                                KeyValue = kvp
                            })).Where(item => item.KeyValue.Key == kvp.Key);

                            if (result.Count() < 1)
                            {
                                continue;
                            }
                            if (result.Count() > 1)
                            {
                                int groupCount = result.GroupBy(result => result.KeyValue.Value.ToString()).Count();
                                if (groupCount > 1)
                                {
                                    LangValueSelectItem item = new LangValueSelectItem
                                    {
                                        LanguageFileName = Path.GetFileName(langfile.FilePath),
                                        Section = sec.Key,
                                        KeyValue = kvp
                                    };
                                    results.Add(item, result);
                                    continue;
                                }
                            }
                            kvp.Value.Value = result.FirstOrDefault().KeyValue.Value;
                        }
                    }
                }
            });

            int remainCount = results.Count();
            foreach (var result in results)
            {
                string msg = $"{result.Key.KeyValue.Key}={result.Key.KeyValue.Value}    (语言文件:{result.Key.LanguageFileName}|| 节点:[{result.Key.Section}])的语言值改为：";
                LangValueSelectItem item = SelectItemDialog.Show($"请选择语言值({remainCount--})", msg, result.Value.ToArray()) as LangValueSelectItem;
                if (item == null)
                {
                    if (MessageBox.Show("询问", "是否退出选择?", MessageBoxButtons.YesNo) == DialogResult.Yes)
                    {
                        return;
                    }
                    continue;
                }
                result.Key.KeyValue.Value.Value = item.KeyValue.Value;
            }
        }

        /// <summary>
        /// 从语言包导入语言值给标注处
        /// </summary>
        /// <returns></returns>
        public async Task ImportLangValueFromPak()
        {
            if (CurrentPackage == null)
            {
                MessageBox.Show("请先导入语言包");
                return;
            }

            FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();
            folderBrowserDialog.Description = "选择一个语言包";
            Dictionary<LangValueSelectItem, IEnumerable<LangValueSelectItem>> results = new Dictionary<LangValueSelectItem, IEnumerable<LangValueSelectItem>>();
            if (folderBrowserDialog.ShowDialog() != DialogResult.OK)
            {
                return;
            }
            await Task.Run(() => {
                string selectedPath = folderBrowserDialog.SelectedPath;
                LanguagePackage newLangugePak = new LanguagePackage(selectedPath);
                newLangugePak.Load();
                foreach (LanguageFile langfile in CurrentPackage.LanguageFiles)
                {
                    foreach (var sec in langfile.GetIniCache())
                    {
                        foreach (var kvp in sec.Value)
                        {
                            var annotions = AnnotationManager.GetAnnotations(Path.GetFileName(langfile.FilePath));
                            if (annotions == null)
                            {
                                continue;
                            }
                            var annotion = annotions.FirstOrDefault(item => item.Contains(kvp.Key + "=" + kvp.Value));
                            if (annotion == null)
                            {
                                continue;
                            }

                            var matchLngFile = newLangugePak.LanguageFiles.FirstOrDefault(item => item.Name.Equals(langfile.Name));
                            if (matchLngFile != null)
                            {
                                var cache= matchLngFile.GetIniCache();
                                if (cache.ContainsKey(sec.Key)&& cache[sec.Key].ContainsKey(kvp.Key))
                                {
                                    kvp.Value.Value = cache[sec.Key][kvp.Key].Value;
                                    continue;
                                }
                            }

                            var result = newLangugePak.LanguageFiles.SelectMany(langfile => langfile.GetIniCache().SelectMany(sec => sec.Value
                            .Select(kvp => new LangValueSelectItem
                            {
                                LanguageFileName = Path.GetFileName(langfile.FilePath),
                                Section = sec.Key,
                                KeyValue = kvp
                            }))).Where(item => item.KeyValue.Key == kvp.Key);

                            if (result.Count() < 1)
                            {
                                continue;
                            }
                            if (result.Count() > 1)
                            {
                                int groupCount = result.GroupBy(result => result.KeyValue.Value.ToString()).Count();
                                if (groupCount > 1)
                                {
                                    LangValueSelectItem item = new LangValueSelectItem
                                    {
                                        LanguageFileName = Path.GetFileName(langfile.FilePath),
                                        Section = sec.Key,
                                        KeyValue = kvp
                                    };
                                    results.Add(item, result);
                                    continue;
                                }
                                else
                                {
                                    int i = 0;
                                }
                            }
                            kvp.Value.Value = result.FirstOrDefault().KeyValue.Value;
                        }
                    }
                }
            });

            int remainCount = results.Count();
            foreach (var result in results)
            {
                string msg = $"{result.Key.KeyValue.Key}={result.Key.KeyValue.Value}    (语言文件:{result.Key.LanguageFileName}|| 节点:[{result.Key.Section}])的语言值改为：";
                LangValueSelectItem item = SelectItemDialog.Show($"请选择语言值({remainCount--})", msg, result.Value.ToArray()) as LangValueSelectItem;
                if (item == null)
                {
                    if (MessageBox.Show("是否退出选择", "询问?", MessageBoxButtons.YesNo) == DialogResult.Yes)
                    {
                        return;
                    }
                    continue;
                }
                result.Key.KeyValue.Value.Value=item.KeyValue.Value;
            }
        }



        /// <summary>
        /// 另存为
        /// </summary>
        /// <param name="UpdateStatusBar"></param>
        /// <param name="extension"></param>
        public void SaveAs(Action<string> UpdateStatusBar,string extension="")
        {
            if (CurrentPackage == null)
            {
                MessageBox.Show("请先导入语言包");
                return;
            }

            FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();
            folderBrowserDialog.Description = "请选择一个文件夹";
            if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
            {
                string selectedPath = folderBrowserDialog.SelectedPath;
                if (!Directory.Exists(selectedPath))
                {
                    Directory.CreateDirectory(selectedPath);
                }
                extension = extension == null ? ".lng" : extension;
                foreach (LanguageFile file in this.CurrentPackage.LanguageFiles)
                {
                    if (file.GetIniCache().Count == 0)
                    {
                        continue;
                    }
                    file.WriteStream(Path.Combine(selectedPath, Path.GetFileName(file.Name + extension)));
                }
                UpdateStatusBar.Invoke($"语言包已另存为至{selectedPath}");
            }
        }

        /// <summary>
        /// 保存
        /// </summary>
        /// <param name="UpdateStatusBar"></param>
        public void Save(Action<string> UpdateStatusBar)
        {
            if (CurrentPackage == null)
            {
                MessageBox.Show("请先导入语言包");
                return;
            }

            if (MessageBox.Show($"是否存储当前文件至{CurrentPackage.Folder}? ", "保存", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
            {
                return;
            }
            CurrentPackage.Write();
            UpdateStatusBar?.Invoke($"当前语言包已保存至{CurrentPackage.Folder}");
        }

        /// <summary>
        /// 获取当前选择语言文件的文本
        /// </summary>
        /// <returns></returns>
        public string GetSelectedText()
         {
            if (CurrentPackage == null)
            {
                return "";
            }

            var lngFile= CurrentPackage.LanguageFiles.FirstOrDefault(item => 
            Path.GetFileName(item.FilePath) == SelectedLngFileName);

            if (lngFile == null)
            {
                return string.Empty;
            }

            if (string.IsNullOrEmpty(SelectedSectionName))
            {
                return lngFile.GetText();
            }

            return lngFile.GetSectionText(SelectedSectionName);
        }

        /// <summary>
        /// 保存编辑的文本
        /// </summary>
        /// <param name="text"></param>
        public void SaveEditingText(string text)
        {
            if (CurrentPackage == null)
            {
                return;
            }
            LanguageFile file = CurrentPackage.LanguageFiles.FirstOrDefault(item => Path.GetFileName(item.FilePath) == SelectedLngFileName);
            if (file == null) { return; }
            if (string.IsNullOrEmpty(SelectedSectionName))
                file.Reload(text);
            else
                file.ReloadSection(text, SelectedSectionName);
        }

        #endregion

        #endregion
    }
}
